home *** CD-ROM | disk | FTP | other *** search
/ Interactive Web Graphics with Shout 3D / Interactive Web Graphics With Shout 3D.iso / pc / Shout3Ddemo / Shout3d_runtime / codebase / applets / PyramidTestPanel.java < prev    next >
Text File  |  2000-09-01  |  7KB  |  246 lines

  1. /**    
  2.     Company:        Eyematic Interfaces
  3.     Project:        Shout3D 2.0 Sample Code
  4.     Class:            PyramidTestPanel
  5.     Date:            April 26, 1999
  6.     Description:    Class for panel in which you click-drag to scale some pyramids
  7.     (C) Copyright Eyematic Interfaces, Inc. - 1997-2000 - All rights reserved
  8.  */
  9.  
  10. package applets;
  11.  
  12. //Include this in order to be able to work
  13. //with nodes in the custom_nodes package
  14. import custom_nodes.*;
  15.  
  16. import java.applet.*;
  17. import java.awt.*;
  18. import java.awt.image.*;
  19. import java.io.*;
  20. import java.util.Date;
  21. import java.net.URL;
  22. import shout3d.*;
  23. import shout3d.core.*;
  24.  
  25. /**
  26.  * PyramidTestPanel
  27.  * 
  28.  * Shows how custom nodes can be added to Shout3D
  29.  * and used in applets.
  30.  * 
  31.  * This applet creates three Pyramid nodes (a custom node in the
  32.  * custom_nodes directory) and then changes their fields when
  33.  * the user click-drags them.
  34.  * 
  35.  * 
  36.  * @author Dave Westwood
  37.  * @author Paul Isaacs
  38.  * @author Jim Stewartson
  39.  */
  40.  
  41. public class PyramidTestPanel extends Shout3DPanel implements DeviceObserver {
  42.     
  43.     // 3 Pyramids to be displayed and manipulated in the scene.
  44.     Pyramid pyramid0, pyramid1, pyramid2;
  45.     
  46.     // For determining which pyramid is clicked with the mouse.
  47.     Picker myPicker;
  48.     Node[] pathToPick;
  49.  
  50.     /**
  51.      * Constructor
  52.      */
  53.     public PyramidTestPanel(Shout3DApplet applet){
  54.         super(applet);
  55.     }
  56.     
  57.     float[] lavender = { .6f, .6f, 1 };
  58.     float[] seafoam  = { .6f,  1f, .6f };
  59.     float[] gray     = { .6f, .6f, .6f };
  60.     
  61.     float[] pos0 = { -4, 0, 0 };
  62.     float[] pos1 = {  0, 0, 0 };
  63.     float[] pos2 = {  4, 0, 0 };
  64.      
  65.     float[] rot0 = {  0, 1, 0, .8f };
  66.     float[] rot1 = {  0, 1, 0,  0 };
  67.     float[] rot2 = {  0, 1, 0, -.8f };
  68.     
  69.     /**
  70.      *
  71.      * This method is automatically called by the parent class Shout3DPanel
  72.      * at the correct time during initialize().
  73.      * 
  74.      * Subclasses should implement this to perform any custom initialization tasks.
  75.      */    
  76.     public void customInitialize() {
  77.         
  78.         // Create the three pyramids
  79.         pyramid0 = new Pyramid();    
  80.         pyramid1 = new Pyramid();    
  81.         pyramid2 = new Pyramid();    
  82.         
  83.         // Get a transform for each pyramid, passing in pretty colors
  84.         Transform xf0 = createXf( pyramid0, lavender );
  85.         Transform xf1 = createXf( pyramid1, seafoam );
  86.         Transform xf2 = createXf( pyramid2, gray );
  87.         
  88.         // Position them relative to each other:
  89.         xf0.translation.setValue(pos0);
  90.         xf1.translation.setValue(pos1);
  91.         xf2.translation.setValue(pos2);
  92.         xf0.rotation.setValue(rot0);
  93.         xf1.rotation.setValue(rot1);
  94.         xf2.rotation.setValue(rot2);
  95.         
  96.         // Add to the scene
  97.         Node[] newKids = new Node[3];
  98.         newKids[0] = xf0;
  99.         newKids[1] = xf1;
  100.         newKids[2] = xf2;
  101.         getScene().addChildren(newKids);
  102.         
  103.         // Move the camera back
  104.         Viewpoint myVP = (Viewpoint) getCurrentBindableNode("Viewpoint");
  105.         myVP.position.getValue()[2] = 10;
  106.         //notify
  107.         myVP.position.setValue(myVP.position.getValue());
  108.         
  109.         // Allocate the picker
  110.         myPicker = getNewPicker();
  111.         
  112.         //Watch for mouse events to do the picking.
  113.         this.addDeviceObserver(this, "MouseInput", null);
  114.         //Register to watch rendering. We'll want to change pyramid
  115.         //fields between renders so that field don't change during
  116.         //mid-multithreaded-render
  117.         getRenderer().addRenderObserver(this,null);
  118.         
  119.         //Call the parent class
  120.         super.customInitialize();
  121.     }
  122.     
  123.     /**
  124.      * Finalize
  125.      */
  126.     protected void finalize()throws Throwable {
  127.         getRenderer().removeRenderObserver(this);
  128.         this.removeDeviceObserver(this, "MouseInput");
  129.         super.finalize();
  130.     }
  131.  
  132.     Node    pathTail;
  133.     Pyramid selectedPyramid;
  134.     float   startWidth, startHeight, startDepth;
  135.     int        startCursorX, startCursorY;
  136.     boolean waitingToChangeFields = false;
  137.     float nextWidth  = 1;
  138.     float nextHeight = 1;
  139.     float nextDepth  = 1;
  140.     
  141.     /** 
  142.      * Called when Mouse input is received.
  143.      * 
  144.      * On mouse DOWN, checks for selection of one of the pyramids.
  145.      * Remembers which pyramid, and starting cursor location.
  146.      * 
  147.      * On mouse DRAG, scales the selected pyramid.
  148.      * Horizontal motion scales width,depth.
  149.      * Vertical motion scales height.
  150.      *  
  151.      */
  152.     public boolean onDeviceInput(DeviceInput di, Object userData){
  153.         //No need to check type of deviceInput, only registered for Mouse Input.
  154.         MouseInput mi = (MouseInput) di;
  155.         if (mi.which == MouseInput.DOWN){
  156.  
  157.             // Perform a pick and see if one of the pyramids was picked.
  158.             //
  159.             selectedPyramid = null;
  160.             pathToPick = myPicker.pickClosest(mi.x,mi.y);
  161.             if (pathToPick!=null && pathToPick.length > 0){
  162.                 pathTail = pathToPick[pathToPick.length-1];
  163.                 if (pathTail instanceof Pyramid){
  164.                     selectedPyramid = (Pyramid) pathTail;
  165.                     
  166.                     startCursorX = mi.x;
  167.                     startCursorY = mi.y;
  168.                     startWidth  = selectedPyramid.width.getValue();
  169.                     startHeight = selectedPyramid.height.getValue();
  170.                     startDepth  = selectedPyramid.depth.getValue();
  171.  
  172.                     //This input was used
  173.                     return true;
  174.                 }
  175.             }
  176.         }
  177.         else if (mi.which == MouseInput.DRAG){
  178.             // Based on mouse motion, change fields of currentPyramid.
  179.             
  180.             // Width and depth change equally with horizontal motion,
  181.             // Height changes with vertical motion.
  182.             // Change by 1 unit every 100 pixels
  183.             nextWidth  = startWidth  + (float)(mi.x-startCursorX)/100;
  184.             nextHeight = startHeight - (float)(mi.y-startCursorY)/100;
  185.             nextDepth  = startDepth  + (float)(mi.x-startCursorX)/100;
  186.             
  187.             // Clamp values to be > 0.1
  188.             if (nextWidth  < 0.1) nextWidth  = 0.1f;
  189.             if (nextHeight < 0.1) nextHeight = 0.1f;
  190.             if (nextDepth  < 0.1) nextDepth  = 0.1f;
  191.             
  192.             // Don't set the field values now.
  193.             // Let them be set during onPreRender so that
  194.             // the field change occurs between renders.
  195.             waitingToChangeFields = true;
  196.             
  197.             // Used the input
  198.             return true;
  199.         }
  200.         //Did not care about this input
  201.         return false;
  202.     }
  203.     
  204.     /**
  205.      * Changing the fields should be done between renders.
  206.      * This is because rendering happens in a different thread,
  207.      * and updating the fields during a render can cause unpleasant
  208.      * flashing.
  209.      * 
  210.      * Note that no onPostRender() method is implemented in this class,
  211.      * even though it is required for all classes implementing RenderObserver.
  212.      * This is because the super class implements RenderObserver fully 
  213.      * and onPostRender is inherited.  
  214.      * Hence this class needs only to override the onPreRender() method, 
  215.      * making sure to call super.onPreRender(r,userData) within the body 
  216.      * of the method.
  217.      */
  218.     public void onPreRender(Renderer r, Object userData){
  219.         super.onPreRender(r, userData);
  220.         if (selectedPyramid != null && waitingToChangeFields){
  221.             selectedPyramid.width.setValue(nextWidth);
  222.             selectedPyramid.height.setValue(nextHeight);
  223.             selectedPyramid.depth.setValue(nextDepth);
  224.             waitingToChangeFields = false;
  225.         }
  226.     }
  227.     
  228.     Transform createXf( Pyramid pyr, float[/*3*/] color ) {
  229.         Material newMat = new Material();
  230.         newMat.diffuseColor.setValue(color);
  231.  
  232.         Appearance newApp = new Appearance();
  233.         newApp.material.setValue(newMat);
  234.         
  235.         shout3d.core.Shape newShape = new shout3d.core.Shape();
  236.         newShape.geometry.setValue(pyr);
  237.         newShape.appearance.setValue( new Appearance[] { newApp });
  238.  
  239.         Transform newXf = new Transform();
  240.         Node[] kids = new Node[1];
  241.         kids[0] = newShape;
  242.         newXf.addChildren(kids);
  243.         return newXf;
  244.     }
  245. }
  246.